package net.facelib.jni;

import java.io.File;
import java.util.concurrent.atomic.AtomicLong;

import com.gitee.l0km.com4j.base.ConditionChecks;
import com.gitee.l0km.com4j.base.SimpleLog;
import com.google.common.base.Strings;

import net.facelib.akcore.AuthParameter;
import net.facelib.akcore.LicenseManager;
import net.facelib.akcore.LicenseUtils;
import net.facelib.akcore.LicenseUtils.NotfoundLicenseManagerException;
import net.facelib.akcore.NativeProductStatus;
import net.facelib.akcore.ProductInitStatus;

import static com.google.common.base.Preconditions.checkNotNull;
import static net.facelib.jni.BridgeLog.BRIDEG_LOGGER;

/**
 * MTFSDK for android/arm JNI 接口<br>
 * 此类为非线程安全的，不可多线程共享调用，需要在外部进一步封装实现线程安全
 * @author guyadong
 *
 */
public abstract class BaseJniBridge implements SdkRuntime.RuntimeConsumer, DynamicLoadResource {
	/**
	 * 互斥对象，确保init和destroy操作互斥
	 */
	protected final Object mutex = new Object();
	protected BaseJniBridge() {
	}
	/**
	 * 执行SDK初始化,初始化失败则抛出异常<br>
	 * {@code licenseKey,licenseCode}用于兼容旧版本授权系统生成的授权关键字和授权码,当此两个参数不为空时,
	 * 如果算法模块支持旧版本授权系统验证，算法初始化时会尝试使用此两个参数验证授权是否合法
	 * @param licenseFile 授权文件路径('\0'结尾)
	 * @param licenseKey 兼容旧版授权系统的授权关键字('\0'结尾)
	 * @param licenseCode 兼容旧版授权系统的授权码('\0'结尾)
	 * @throws SdkInitException 
	 */
	protected abstract void sdkInit(String licenseFile, String licenseKey, String licenseCode) throws SdkInitException;
	/**
	 * 执行SDK卸载初始化
	 */
	protected abstract void sdkUninit() ;
	
	/**
	 * 返回当前授权管理器实例
	 * @return {@link LicenseManager}实例
	 */
	protected abstract LicenseManager licenseManager();

	@Override
	public void init() throws SdkInitException{
		synchronized (mutex) {
			try {
				LicenseManager manager = licenseManager();
				if(manager != null){
					/** 使用 IM_AK,IM_OL两种方式尝试初始化,任何一种方式初始化成功就将 initModes 置为此模式
					 * 如果两种方式都初始化失败则抛出异常 */
					String licenseFile = manager.provider().stringOf(AuthParameter.LICENSE_FILE);
					StringBuilder builder = new StringBuilder();
					if(!Strings.isNullOrEmpty(licenseFile)){
						try {
							ConditionChecks.checkTrue(new File(licenseFile).isFile(), 
									SdkInitException.class, "NOT FOUND licenseFile %s",licenseFile);
							String szLicenseFile = manager.provider().zeroEndStringOf(AuthParameter.LICENSE_FILE);
							sdkInit(szLicenseFile, "\0", "\0");
							BRIDEG_LOGGER.log("init {}", this);
							return;
						} catch (SdkInitException e) {
							builder.append(SimpleLog.logString("[AM_AK] init fail cause by {}({}) ", e.status.getEnumName(),e.status.getMessage()));
						}
					}
					String szLicenseKey = manager.provider().zeroEndStringOf(AuthParameter.LICENSE_KEY_OLD);
					String szLicenseCode = manager.provider().zeroEndStringOf(AuthParameter.LICENSE_CODE_OLD);
					if(null != szLicenseKey && szLicenseCode != null){
						try{
							sdkInit("\0", szLicenseKey, szLicenseCode);
							BRIDEG_LOGGER.log("init {}", this);
							return;
						} catch (SdkInitException e) {
							builder.append(SimpleLog.logString("[AM_OL] init fail cause by {}({}) ", e.status.getEnumName(),e.status.getMessage()));
						}
					}
					throw new SdkInitException(builder.toString(),ProductInitStatus.PRODUCT_INIT_FAIL);
				}else{
					/* 不需要授权,填入空字符串 */
					sdkInit("\0", "\0", "\0");
					BRIDEG_LOGGER.log("init {}", this);
				}
			} catch (SdkInitException e) {
				BRIDEG_LOGGER.log("{}:{}",e.getClass().getName(),e.getMessage());
				BRIDEG_LOGGER.logTrace(true, e);
				throw e;
			}catch (Throwable e) {
				BRIDEG_LOGGER.log("{}:{}",e.getClass().getName(),e.getMessage());
				BRIDEG_LOGGER.logTrace(true, e);
				throw new SdkInitException(e);
			}
		}
	}

	@Override
	public void destroy() {
		synchronized (mutex) {
			BRIDEG_LOGGER.log("sdkUninit {}", this);
			sdkUninit();
		}		
	}
	@Override
	public BaseJniBridge setRuntimeParam(String name, Object value) throws SdkRuntimeException {
		return this;
	}
	/**
	 * 懒加载方式返回SPI方式加载的授权管理器接口实例,如果没有找到则抛出异常
	 * @param productId 产品ID
	 * @param defaultLicenseManager  默认实例
	 * @return 与productId匹配的{@link LicenseManager}实例
	 * @throws NotfoundLicenseManagerException 
	 */
	public static LicenseManager getLicenseManager(String productId, LicenseManager defaultLicenseManager) throws NotfoundLicenseManagerException {
		return LicenseUtils.getLicenseManager(productId, defaultLicenseManager);			
	}
	/**
	 * 测试是否可以正常初始化算法实例
	 * @param initMills [out]如果不为{@code null}返回返回初始化耗时(毫秒)
	 * @param bridgeType 算法实例类型
	 * @return 产品初始化状态
	 */
	public static <T extends DynamicLoadResource>ProductInitStatus testInit(AtomicLong initMills,Class<T>bridgeType) {
		
		T tmp;
		try {
			tmp = checkNotNull(bridgeType,"bridgeType is null").newInstance();
		} catch (Throwable e) {
			BRIDEG_LOGGER.log("{}:{}",e.getClass().getName(),e.getMessage());
			BRIDEG_LOGGER.logTrace(true, e);
			return ProductInitStatus.UNKNOW_ERROR;
		}
		BRIDEG_LOGGER.log("begin {} ", tmp);
		NativeProductStatus initStatus;
		try {
			long begin = System.currentTimeMillis();
			tmp.init();
			initStatus = tmp.getStatus();
			if(null != initMills ){
				initMills.set(System.currentTimeMillis() - begin);	
			}
		} catch (SdkInitException e) {
			initStatus = tmp.getStatus();
			BRIDEG_LOGGER.log("{}:{}",e.getClass().getName(),e.getMessage());
			BRIDEG_LOGGER.logTrace(true, e);
		} catch (Throwable e) {
			BRIDEG_LOGGER.log("{}:{}",e.getClass().getName(),e.getMessage());
			BRIDEG_LOGGER.logTrace(true, e);
			return ProductInitStatus.UNKNOW_ERROR;
		}finally {
			tmp.destroy();
		}
		ProductInitStatus productInitStatus = ProductInitStatus.asProductStatus(initStatus);
		BRIDEG_LOGGER.log("done {} {}", tmp, productInitStatus);
		return productInitStatus;
	}
}
